home *** CD-ROM | disk | FTP | other *** search
/ AOL File Library: 2,801 to 2,900 / aol-file-protocol-4400-2801-to-2900.zip / AOLDLs / C++ Files Library / HyperCuber Source / HyperCuber 2.0 Source.sit / HyperCuber 2.0 Source / CGraphic.cp < prev    next >
Text File  |  1994-05-03  |  26KB  |  919 lines

  1. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2. //| This file contains the implementation of the Graphic class.  A Graphic is a
  3. //| collection of graphics primitives.
  4. //|________________________________________________________________________________
  5.  
  6.  
  7. #include "CGraphic.h"
  8. #include "CHyperCuberPane.h"
  9. #include "CHyperCuberPrefs.h"
  10. #include "CPath.h"
  11. #include "CPolygon.h"
  12. #include "CPPoint.h"
  13. #include "CPrimitive.h"
  14. #include <LongQD.h>
  15.  
  16. #include <math.h>
  17. #include <string.h>
  18. #include <stdlib.h>
  19.  
  20.  
  21. //============================= Protypes ==============================\\
  22.  
  23. extern double **CreateRotMatrix(long dim, double *angles);
  24. extern void UpdateRotMatrix(long i, double old_value, double new_value, long dim, 
  25.                             double **matrix_handle);
  26. extern void RotateVector(double *vector, double *rotated_vector, long dim, double *matrix);
  27. extern void BuildRotMatrix(long dim, double *angles, double **matrix_handle);
  28. void ProjectVector(double *point, double *proj_point, long dimension, short persp_index);
  29.  
  30.  
  31. //============================= Constants ==============================\\
  32.  
  33. #define    Pi                3.14159265358979323846
  34. #define EYE_SEPARATION    Pi/30
  35.  
  36.  
  37. //===================================== Globals =====================================\\
  38.  
  39. extern CHyperCuberPrefs        *gPrefs;        //  The preferences
  40.  
  41.  
  42.  
  43. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  44. //| CGraphic::IGraphic
  45. //|
  46. //| Purpose: Initialize a Graphic.
  47. //|
  48. //| Parameters: none
  49. //|_________________________________________________________
  50.  
  51. void    CGraphic::IGraphic(void)
  52. {
  53.  
  54.     primitives = new(CList);                            //  Initialize the primitives list
  55.     primitives->IList();
  56.  
  57.     colors = new(CList);                                //  Initialize the colors list
  58.     colors->IList();
  59.  
  60.     vertices = new(CList);                                //  Initialize the vertices lists
  61.     vertices->IList();
  62.     stereo_vertices = new(CList);    
  63.     stereo_vertices->IList();
  64.  
  65.     rotation_matrices = new(CList);                        //  Initialize the rotation matrices lists
  66.     rotation_matrices->IList();
  67.     stereo_matrices = new(CList);
  68.     stereo_matrices->IList();
  69.  
  70.     angles = new(CList);
  71.     angles->IList();
  72.  
  73. }    //==== CGraphic::IGraphic() ====\\
  74.  
  75.  
  76.  
  77. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  78. //| CGraphic::Dispose
  79. //|
  80. //| Purpose: Dispose of a Graphic
  81. //|
  82. //| Parameters: none
  83. //|_________________________________________________________
  84.  
  85.     void dispose_handle(CObject *object)
  86.     {
  87.         DisposeHandle((Handle) object);
  88.     }
  89.  
  90.  
  91. void    CGraphic::Dispose(void)
  92. {
  93.  
  94.     primitives->DisposeAll();                            //  Dispose of the primitives
  95.  
  96.     long i;
  97.     for (i=1; i <= num_vertices; i++)
  98.         DisposeHandle((Handle) vertices->NthItem(i));    //  Dispose of the vertices lists
  99.     
  100.     for (i=1; i <= 2; i++)
  101.         DisposeHandle(
  102.                 (Handle) stereo_vertices->NthItem(i));    //  Dispose of the stereo vertices lists
  103.  
  104.     vertices->Dispose();                                //  Dispose of the lists of vertices lists
  105.     stereo_vertices->Dispose();
  106.  
  107.     for (i=3; i <= dimension; i++)
  108.         DisposeHandle(
  109.                 (Handle) rotation_matrices->NthItem(i));//  Dispose of the rotation matrices
  110.  
  111.     DisposeHandle((Handle) stereo_matrices->NthItem(3));//  Dispose of the stereo rotation matrix
  112.  
  113.     rotation_matrices->Dispose();                        //  Dispose of the rotation matrices lists
  114.     stereo_matrices->Dispose();
  115.  
  116.     angles->DoForEach(dispose_handle);
  117.     angles->Dispose();
  118.  
  119.     DisposHandle((Handle) perspective_params);            //  Dispose of the perspective parameters
  120.  
  121. }    //==== CGraphic::Dispose() ====\\
  122.  
  123.  
  124.  
  125. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  126. //| CGraphic::SetupGraphic
  127. //|
  128. //| Purpose: Set up a those parts of the graphic which depend on the dimension.
  129. //|
  130. //| Parameters: n: the dimension of this graphic
  131. //|_____________________________________________________________________________
  132.  
  133. void CGraphic::SetupGraphic(long n)
  134. {
  135.  
  136.     dimension = n;
  137.  
  138.     rotation_matrices->Append((CObject *) NULL);    //  Fill in null fields in the sines,
  139.     rotation_matrices->Append((CObject *) NULL);    //    cosines, or rotation matrix for
  140.     stereo_matrices->Append((CObject *) NULL);        //    1D and 2D, since we don't do 1D or
  141.     stereo_matrices->Append((CObject *) NULL);        //    2D rotations
  142.     angles->Append((CObject *) NULL);
  143.     angles->Append((CObject *) NULL);
  144.     
  145.     long i;
  146.     for (i=3; i <= dimension; i++)
  147.         {
  148.  
  149.         double **angles_array =
  150.             (double **) NewHandle(sizeof(double)*(i-1));//  Allocate space for angles
  151.         
  152.         long j;
  153.         for (j = 0; j <= i-2; j++)                        //  Fill in the sines and cosines array
  154.             (*angles_array)[j] = 0;
  155.  
  156.         if (i == 3)
  157.             {
  158.             (*angles_array)[0] = 5*Pi/6;                //  Special view for 3D
  159.             (*angles_array)[1] = 5*Pi/6;
  160.             }
  161.             
  162.         HLock((Handle) angles_array);
  163.         double **matrix = CreateRotMatrix(i,
  164.                                         *angles_array);    //  Create this rotation matrix
  165.                                     
  166.         angles->Append((CObject *) angles_array);        //  Add this angles array to the list
  167.         
  168.         rotation_matrices->Append((CObject *) matrix);    //  Add this matrix to the list
  169.  
  170.         if (i == 3)
  171.             {
  172.             (*angles_array)[0] = 5*Pi/6 + EYE_SEPARATION;    //  Offset angle to provide other stereo view
  173.             
  174.             matrix = CreateRotMatrix(i, *angles_array);    //  Create another matrix for 3D stereo
  175.  
  176.             stereo_matrices->Append((CObject *) matrix);//  This matrix is used for stereo
  177.         
  178.             (*angles_array)[0] = 5*Pi/6;                //  Restore angle to normal
  179.             
  180.             }
  181.         else
  182.         
  183.             stereo_matrices->Append((CObject *) matrix);//  Add this matrix to the stereo list
  184.  
  185.         HUnlock((Handle) angles_array);
  186.  
  187.         }
  188.  
  189.     perspective_params =                                //  Allocate space for the perspective parms
  190.             (long **) NewHandle(sizeof(long)*dimension);
  191.  
  192.     for (i = 0; i < dimension; i++)
  193.         (*perspective_params)[i] = 3;                    //  Make all perspective parameters 3
  194.     
  195.     (*perspective_params)[2] =
  196.         (*perspective_params)[3] = 7;                    //  ...except dimensions 3 and 4; then use 7
  197.     
  198.     
  199. }    //==== CGraphic::SetupGraphic() ====\\
  200.  
  201.  
  202.  
  203. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  204. //| Operator >> for extracting a CGraphic
  205. //|
  206. //| Purpose: Read the graphic from the stream
  207. //|
  208. //| Parameters: none
  209. //|__________________________________________________________________________
  210.  
  211. istream& operator>> (istream& s, CGraphic& graphic)
  212. {
  213.  
  214. enum {
  215.     point = 1,
  216.     path,
  217.     polygon
  218.     };
  219.  
  220.     if (!s.ipfx)
  221.         return s;
  222.  
  223.     long version;
  224.     s >> version;                                        //  Get the version number
  225.     
  226.     long dimension;
  227.     s >> dimension;                                        //  Get the dimensions of the image
  228.     
  229.     graphic.SetupGraphic(dimension);
  230.         
  231.     short reserved;
  232.     s >> reserved;                                        //  Ignore the reserved fields
  233.     s >> reserved;
  234.     
  235.     long num_vertices;
  236.     s >> num_vertices;                                    //  Get the number of vertices
  237.     graphic.num_vertices = num_vertices;
  238.  
  239.     Point **screen_point_array =                    //  Allocate space for screen point array
  240.             (Point **) NewHandle(
  241.                         num_vertices*sizeof(Point));
  242.     
  243.     graphic.vertices->Append(
  244.                     (CObject *) screen_point_array);    //  Put the screen point array in the
  245.                                                         //    1D vertices spot (since there are no
  246.                                                         //    1D vertices to store there)
  247.     
  248.     Point **stereo_screen_point_array =                    //  Allocate space for the other screen point
  249.                         (Point **) NewHandle(            //    array (used for stereo).
  250.                             num_vertices*sizeof(Point));
  251.     
  252.     graphic.stereo_vertices->Append(
  253.                 (CObject *) stereo_screen_point_array);    //  Put the other screen point array in 1D
  254.     
  255.     double **vertex_list;
  256.     long i;
  257.     for (i = 2; i <= graphic.dimension; i++)            //  Allocate space for vertex arrays
  258.         {
  259.         
  260.         vertex_list = (double **)NewHandle(                //  Create an array of verticies of dimension i.
  261.                         num_vertices*sizeof(double)*i);    //  Each vertex is an array of coordinates
  262.         
  263.         graphic.vertices->Append(                        //  Add this array to the list of vertex arrays
  264.                     (CObject *) vertex_list);
  265.         
  266.         if (i == 2)
  267.             vertex_list = (double **)NewHandle(            //  Create another array for 2D vertices.
  268.                         num_vertices*sizeof(double)*i);    //    (used for stereo)
  269.             
  270.         graphic.stereo_vertices->Append(                //  Add this to the list of stereo vertex arrays
  271.                             (CObject *) vertex_list);
  272.         }
  273.     
  274.     //  ASSERTION: vertex_list points to space for "real" (unprojected) vertices
  275.     
  276.     double *coordinate = *vertex_list;                    //  Point to first coordinate of
  277.                                                         //    first point
  278.         
  279.     for (i = 1; i <= num_vertices; i++)
  280.         {
  281.  
  282.         char left_paren;
  283.         s >> left_paren;                                //    Get left parenthesis
  284.         
  285.         char comma;
  286.         long j;
  287.         for (j = 1; j<= graphic.dimension; j++)
  288.             {
  289.             s >> *coordinate;                            //  Read in this coordinate
  290.             s >> comma;                                    //  Read the comma (or ")" for last coordinate)
  291.             coordinate++;                                //  Point to next coordinate
  292.             }
  293.         
  294.         // ASSERTION: comma = ")"
  295.         // ASSERTION: coordinate points to first coordinate of next point
  296.         
  297.         }
  298.     
  299.     short num_colors;
  300.     s >> num_colors;                                    //  Get the number of colors
  301.  
  302.     for (i = 1; i <= num_colors; i++)
  303.         {
  304.         RGBColor **color;
  305.         
  306.         color = (RGBColor **)
  307.                 NewHandle(sizeof(RGBColor));            //  Allocate space for color;
  308.         
  309.         char comma;
  310.         s >> (*color)->red >> comma;                    //    Get this color
  311.         s >> (*color)->green >> comma;        
  312.         s >> (*color)->blue;
  313.         
  314.         graphic.colors->Append((CObject *) color);        //  Add this color to the end of the colors list
  315.         }
  316.     
  317.     short num_primitives;
  318.     s >> num_primitives;                                //  Get the number of primitives
  319.  
  320.     for (i = 1; i <= num_primitives; i++)
  321.         {
  322.         
  323.         short primitive_type;
  324.         s >> primitive_type;                            //  Get the primitive type
  325.         
  326.         CPrimitive *primitive;                            //  Create a new primitive of the correct type
  327.         switch(primitive_type)
  328.             {
  329.             case point:
  330.                 primitive = (CPrimitive *) new (CPPoint);
  331.                 ((CPPoint *) primitive)->IPPoint(graphic.colors);
  332.                 s >> *((CPPoint *) primitive);            //  Read the point in from the input stream
  333.                 break;
  334.                 
  335.             case path:
  336.                 primitive = (CPrimitive *) new (CPath);
  337.                 ((CPath *) primitive)->IPath(graphic.colors);
  338.                 s >> *((CPath *) primitive);            //  Read the path in from the input stream
  339.                 break;
  340.                 
  341.             case polygon:
  342.                 primitive = (CPrimitive *) new (CPolygon);
  343.                 ((CPolygon *) primitive)->IPolygon(graphic.colors);
  344.                 s >> *((CPolygon *) primitive);            //  Read the polygon in from the input stream
  345.                 break;
  346.                 
  347.             }
  348.         
  349.         graphic.primitives->Append(primitive);            //  Add this primitive to the end of the list
  350.         
  351.         }
  352.     
  353.     return s;
  354.  
  355. }    //==== operator>> for reading CGraphic from file ====\\
  356.  
  357.  
  358.  
  359. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  360. //| CGraphic::ClearDrawingArea
  361. //|
  362. //| Purpose: Clear the drawing area, in preparation for a Draw
  363. //|
  364. //| Parameters: color: the color to use
  365. //|__________________________________________________________________________
  366.  
  367. void    CGraphic::ClearDrawingArea(RGBColor *color)
  368. {
  369.  
  370.     GrafPtr temp_port;
  371.  
  372.     pane->Prepare();                                    //  Prepare to draw into pane
  373.  
  374.     if (pane->fDrawOffscreen)
  375.         {
  376.         GetPort(&temp_port);
  377.         SetPort((GrafPtr) &(pane->OffscreenPort));        //  Prepare to draw off-screen
  378.         }
  379.  
  380.     Rect pane_rect;                                        //  Find the pane rect
  381.     LongRect long_pane_rect;
  382.     pane->GetFrame(&long_pane_rect);
  383.     LongToQDRect(&long_pane_rect, &pane_rect);
  384.     ClipRect(&pane_rect);
  385.  
  386.     RGBColor temp_color;
  387.     GetBackColor(&temp_color);
  388.     RGBBackColor(color);                                //  Erase the drawing area
  389.     EraseRect(&pane_rect);
  390.     RGBBackColor(&temp_color);
  391.  
  392.     if (pane->fDrawOffscreen)
  393.         SetPort(temp_port);                                //  Restore the old port
  394.  
  395. }    //==== CGraphic::ClearDrawingArea() ====\\
  396.  
  397.  
  398.  
  399. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  400. //| CGraphic::Draw
  401. //|
  402. //| Purpose: Draw the graphic
  403. //|
  404. //| Parameters: none
  405. //|__________________________________________________________________________
  406.  
  407. void    CGraphic::Draw(void)
  408. {
  409.  
  410.     GrafPtr temp_port;
  411.  
  412.     pane->Prepare();                                            //  Prepare to draw into pane
  413.  
  414.     if (pane->fDrawOffscreen)
  415.         {
  416.         GetPort(&temp_port);
  417.         SetPort((GrafPtr) (&pane->OffscreenPort));                //  Prepare to draw off-screen
  418.         }
  419.  
  420.     if (pane->StereoMode == two_color_stereo)                    //  Draw in AddOver mode for 2-img
  421.         PenMode(addOver);
  422.  
  423.     long num_primitives = primitives->GetNumItems();            //  Find the number of primitives
  424.  
  425.     RGBColor *draw_color =
  426.             (pane->fUseNativeColors) ? NULL :
  427.                                         &(pane->GraphicColor);    //  Use same color for all primitives
  428.                                                                 //    if desired
  429.     Boolean fAntialias = pane->fAntialias;
  430.     
  431.     LongRect long_frame_rect;
  432.     Rect frame_rect;
  433.     pane->GetFrame(&long_frame_rect);
  434.     LongToQDRect(&long_frame_rect, &frame_rect);
  435.     
  436.     Point **screen_points = (Point **) vertices->FirstItem();    //  Get screen points list
  437.     
  438.     long i;
  439.     Point **stereo_screen_points;
  440.     Rect left_frame_rect, right_frame_rect;
  441.     switch(pane->StereoMode)
  442.         {
  443.         case mono:
  444.             break;
  445.         
  446.         case two_image_stereo:
  447.  
  448.             left_frame_rect = frame_rect;                        //  Split frame into two square rects
  449.             right_frame_rect = frame_rect;
  450.             
  451.             long frame_height = frame_rect.bottom - frame_rect.top;
  452.             
  453.             left_frame_rect.right -= frame_height;
  454.             right_frame_rect.left += frame_height;        
  455.  
  456.             stereo_screen_points =
  457.                     (Point **) stereo_vertices->FirstItem();    //  Get stereo screen points list
  458.             break;
  459.             
  460.         case two_color_stereo:
  461.  
  462.             stereo_screen_points =
  463.                     (Point **) stereo_vertices->FirstItem();    //  Get stereo screen points list
  464.             break;
  465.             
  466.         }
  467.                     
  468.     for (i = 1; i <= num_primitives; i++)                        //  Draw the primitives
  469.         {
  470.         CPrimitive *primitive =
  471.                     (CPrimitive *) primitives->NthItem(i);        //  Get this primitive
  472.         
  473.         
  474.         switch(pane->StereoMode)
  475.             {
  476.             case mono:
  477.                 ((CPrimitive *) primitives->NthItem(i))->
  478.                                 Draw(draw_color, screen_points,
  479.                                     &frame_rect, fAntialias);    //  Draw the primitive
  480.                 break;
  481.                 
  482.             case two_image_stereo:
  483.                 ((CPrimitive *) primitives->NthItem(i))->
  484.                             Draw(draw_color, screen_points,
  485.                                 &right_frame_rect, fAntialias);    //  Draw primitive (left view)
  486.     
  487.                 ((CPrimitive *) primitives->NthItem(i))->
  488.                             Draw(draw_color, stereo_screen_points,
  489.                                 &left_frame_rect, fAntialias);    //  Draw primitive (right view)
  490.                 break;
  491.                 
  492.             case two_color_stereo:
  493.                 ((CPrimitive *) primitives->NthItem(i))->
  494.                             Draw(&(gPrefs->prefs.right_eye_color),
  495.                                 screen_points,
  496.                                     &frame_rect, fAntialias);    //  Draw primitive (left view)
  497.     
  498.                 ((CPrimitive *) primitives->NthItem(i))->
  499.                             Draw(&(gPrefs->prefs.left_eye_color),
  500.                                 stereo_screen_points,
  501.                                     &frame_rect, fAntialias);    //  Draw primitive (right view)
  502.                 break;
  503.                 
  504.             }
  505.         }
  506.  
  507.     if (pane->StereoMode == two_color_stereo)                    //  Switch back to SrcCopy mode
  508.         PenMode(srcCopy);
  509.  
  510.     if (pane->fDrawOffscreen)                                    //  If we drew offscreen, update the
  511.                                                                 //    pane now
  512.         {
  513.         SetPort(temp_port);                                        //  Restore the old port
  514.  
  515.         pane->Prepare();                                        //  Prepare to update pane
  516.     
  517.         Rect dest_rect;
  518.         LongToQDRect(&(pane->frame), &dest_rect);                //  Get area of pane
  519.     
  520.         RGBColor rgb_white = {0xFFFF, 0xFFFF, 0xFFFF};
  521.         RGBBackColor(&rgb_white);                                //  Make sure background color is white
  522.  
  523.         CopyBits((BitMapPtr) *(pane->OffscreenPort.portPixMap),
  524.                     (BitMapPtr) *(((CGrafPtr)thePort)->portPixMap), 
  525.                     &dest_rect, &dest_rect, srcCopy, NULL);
  526.         }
  527.  
  528.  
  529. }    //==== CGraphic::Draw() ====\\
  530.  
  531.  
  532.  
  533. #if 0
  534.  
  535. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  536. //| CGraphic::DrawAxes
  537. //|
  538. //| Purpose: Draw the n-dimensional axes
  539. //|
  540. //| Parameters: none
  541. //|__________________________________________________________________________
  542.  
  543. void    CGraphic::DrawAxes(void)
  544. {
  545.  
  546.     
  547.  
  548. }    //==== CGraphic::DrawAxes() ====\\
  549.  
  550. #endif
  551.  
  552.  
  553.  
  554. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  555. //| CGraphic::OffsetAngle
  556. //|
  557. //| Purpose: Change one of the angles by some offset.
  558. //|
  559. //| Parameters: dimension: dimension this angle controls
  560. //|             angle:     the angle to change
  561. //|             offset:    the amount to change the angle by
  562. //|__________________________________________________________________________
  563.  
  564. void    CGraphic::OffsetAngle(long dimension, long angle, double offset)
  565. {
  566.  
  567.     double *angles_array =
  568.         *((double **) angles->NthItem(dimension));        //  Find the array of angles
  569.     
  570.     ChangeAngle(dimension, angle,
  571.                     angles_array[angle-1] + offset);    //  Change angle to old value + offset
  572.     
  573. }    //==== CGraphic::OffsetAngle() ====\\
  574.  
  575.  
  576.  
  577. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  578. //| CGraphic::ChangeAngle
  579. //|
  580. //| Purpose: Change one of the angles.
  581. //|
  582. //| Parameters: dimension: dimension this angle controls
  583. //|             angle:     the angle to change
  584. //|             value:     new value of the angle
  585. //|__________________________________________________________________________
  586.  
  587. void    CGraphic::ChangeAngle(long dimension, long angle, double value)
  588. {
  589.  
  590.     double *angles_array =
  591.         *((double **) angles->NthItem(dimension));        //  Find the array of angles
  592.     
  593.     double current_value = angles_array[angle-1];        //  Get the current value of the angle
  594.     angles_array[angle-1] = value;                        //  Change the value to the new value  
  595.  
  596.     double **rotation_matrix =
  597.             ((double **) rotation_matrices->
  598.                                 NthItem(dimension));    //  Get the rotation matrix
  599.  
  600.     // DEBUG: this is a "safer" way to build the matrix
  601.  
  602. //    BuildRotMatrix(dimension, angles_array, rotation_matrix);        //  Build the matrix
  603.  
  604.  
  605.     UpdateRotMatrix(angle-1, current_value, value,
  606.                 dimension, rotation_matrix);            //  Update the rotation matrix
  607.     
  608.     if ((pane->StereoMode != mono) && (dimension == 3))
  609.         {
  610.         
  611.         if (angle == 1)
  612.             {
  613.             value += EYE_SEPARATION;                    //  Offset value slightly for stereo angle
  614.             current_value += EYE_SEPARATION;
  615.             }
  616.                 
  617.         rotation_matrix =
  618.                 ((double **) stereo_matrices->
  619.                                     NthItem(dimension));//  Get the stereo rotation matrix
  620.     
  621.         UpdateRotMatrix(angle-1, current_value, value,
  622.                             dimension, rotation_matrix);//  Update the rotation matrix
  623.     
  624.         }
  625.  
  626.     Project(dimension);                                    //  Project object with new angle
  627.  
  628. }    //==== CGraphic::ChangeAngle() ====\\
  629.  
  630.  
  631.  
  632. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  633. //| CGraphic::SwitchToStereo
  634. //|
  635. //| Purpose: Prepare to stereo viewing mode.
  636. //|
  637. //| Parameters: none
  638. //|______________________________________________________________________
  639.  
  640. void    CGraphic::SwitchToStereo(void)
  641. {
  642.  
  643.     double **rotation_matrix =
  644.                 ((double **) rotation_matrices->
  645.                                     NthItem(3));    //  Get address of 3D rotation matrix
  646.     double **stereo_rotation_matrix =
  647.                 ((double **) stereo_matrices->
  648.                                     NthItem(3));    //  Get address of stereo 3D rotation matrix
  649.     
  650.     BlockMove(*rotation_matrix,
  651.                 *stereo_rotation_matrix,
  652.                     9*sizeof(double));                //  Copy normal rotation matrix to stereo
  653.     
  654.     double *angles_array =
  655.         *((double **) angles->NthItem(3));            //  Find the array of angles
  656.  
  657.     UpdateRotMatrix(0, angles_array[0],
  658.                     angles_array[0] + EYE_SEPARATION,
  659.                     3, stereo_rotation_matrix);        //  Change stereo matrix to stereo view
  660.  
  661.     Project(3);                                        //  Project the object in stereo
  662.  
  663. }    //==== CGraphic::SwitchToStereo() ====\\
  664.  
  665.  
  666.  
  667. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  668. //| CGraphic::ChangePerspective
  669. //|
  670. //| Purpose: Change the amount of perspective.
  671. //|
  672. //| Parameters: dimension:   dimension to change perspective in
  673. //|             perspective: new amount of perspective
  674. //|__________________________________________________________________________
  675.  
  676. void    CGraphic::ChangePerspective(long dimension, long perspective)
  677. {
  678.  
  679.     (*perspective_params)[dimension-1] = perspective;    //  Change the parameter
  680.     
  681.     Project(dimension);                                    //  Project object with new perspective
  682.  
  683. }    //==== ChangePerspective() ====\\
  684.  
  685.  
  686.  
  687. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  688. //| CGraphic::Project
  689. //|
  690. //| Purpose: Project the the vertices from the n-dimensional vertex list 
  691. //|          to the (n-1)-dimensional vertex list.  This also propagates
  692. //|          downward to (n-2), etc, down to 2D and the screen points.
  693. //|
  694. //| Parameters: n: dimension to project from
  695. //|__________________________________________________________________________
  696.  
  697. void    CGraphic::Project(long n)
  698. {
  699.  
  700.     double *point =                                        //  Get handle to first point in the n-D list
  701.                 *((double **) vertices->NthItem(n));    //    vertex list
  702.     double *proj_point =                                //  Get handle to the first point in the
  703.                 *((double **) vertices->NthItem(n-1));    //    (n-1)-D vertex list
  704.     
  705.     double *stereo_point;
  706.     double *stereo_proj_point;
  707.     double *stereo_rotmatrix;
  708.     if ((pane->StereoMode != mono) && (n == 3))
  709.         {
  710.         stereo_point = *((double **)
  711.                         stereo_vertices->NthItem(3));    //  Handle to the first point in 3D list
  712.  
  713.         stereo_proj_point = *((double **)
  714.                         stereo_vertices->NthItem(2));    //    2D stereo vertex list
  715.  
  716.         stereo_rotmatrix = *((double **)
  717.                         stereo_matrices->NthItem(n));    //  Get the rotation matrix
  718.         }
  719.     
  720.     double **rotated_point_handle =
  721.             (double **) NewHandle(sizeof(double) * n);
  722.     double *rotated_point = *rotated_point_handle;
  723.  
  724.     double *rotmatrix =                                    //  Get the rotation matrix
  725.             *((double **) rotation_matrices->NthItem(n));
  726.  
  727.     long vertex;
  728.     for (vertex = 1; vertex <= num_vertices; vertex++)
  729.         {
  730.         
  731.         RotateVector(point, rotated_point, n, rotmatrix);    //  Rotate this point
  732.         ProjectVector(rotated_point, proj_point, n,
  733.                         (*perspective_params)[n-1]);        //  Project this point
  734.  
  735.         point += n;                                            //  Point to next n-D point
  736.         proj_point += (n-1);                                //  Point to next (n-1)-D point
  737.  
  738.         if ((pane->StereoMode != mono) && (n == 3))            //  Do the same for the stereo view
  739.             {
  740.     
  741.             RotateVector(stereo_point, rotated_point, n,
  742.                             stereo_rotmatrix);                //  Rotate this point
  743.             ProjectVector(rotated_point, stereo_proj_point,
  744.                             n, (*perspective_params)[n-1]);    //  Project this point
  745.             
  746.             stereo_point += n;                                //  Point to next n-D point
  747.             stereo_proj_point += (n-1);                        //  Point to next (n-1)-D point
  748.     
  749.             }
  750.         }
  751.  
  752.     DisposHandle((Handle) rotated_point_handle);            //  Free up memory used by rotated point
  753.  
  754.     if (n > 3)
  755.         Project(n-1);                                        //  Recursively project downward to 3D
  756.  
  757.     else
  758.         FitToPane();                                        //  Map 2D points to screen points
  759.  
  760. }    //==== CGraphic::Project() ====\\
  761.  
  762.  
  763.  
  764. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  765. //| Procedure: ProjectVector
  766. //|
  767. //| Purpose: Project a vector from n-space to (n-1)-space, with perspective
  768. //|          if desired.
  769. //|
  770. //| Parameters: point:       the point to project
  771. //|             proj_point:  receives the projected point
  772. //|             dimension:   the dimension of point
  773. //|             persp_index: the perspective coefficient (0 for no perspective)
  774. //|_____________________________________________________________________________
  775.  
  776. void ProjectVector(double *point, double *proj_point, long dimension, short persp_index)
  777. {
  778.  
  779.     const double persp_table[11] = {0.0, 50.0, 25.5, 15.5, 12.0, 9.0, 6.5, 4.5, 3.0, 2.5, 2.0};
  780.  
  781.     double perspective = persp_table[persp_index];
  782.  
  783.     if (perspective != 0)                            //  Project point with perspective
  784.         {
  785.         double t = perspective /
  786.                 (perspective - point[0]);
  787.         
  788.         if (t<0) t = -t;
  789.         
  790.         long i;
  791.         for (i = 1; i < dimension; i++)
  792.             proj_point[i-1] = t*point[i];
  793.         }
  794.         
  795.     else                                            //  No perspective-- just project it straight
  796.         BlockMove(point+1, proj_point,
  797.                             sizeof(double)*(dimension-1));
  798.         
  799. }    //==== ProjectVector() ====\\
  800.  
  801.  
  802.  
  803. //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  804. //| CGraphic::FitToPane
  805. //|
  806. //| Purpose: Map the 2D vertices to their pane equivalents
  807. //|
  808. //| Parameters: fOtherView: none
  809. //|__________________________________________________________________________
  810.  
  811. void    CGraphic::FitToPane(void)
  812. {
  813.  
  814.     double ymin = -3;
  815.     double ymax = 3;
  816.     double xmin = -3;
  817.     double xmax = 3;
  818.     
  819.     Point *screen_points = *((Point **) vertices->FirstItem());    //  Get pointer to screen points list
  820.     double *points2D = *((double **) vertices->NthItem(2));        //  Get pointer to 2D points list
  821.  
  822.     Point *stereo_screen_points = *((Point **)
  823.                                 stereo_vertices->FirstItem());    //  Get pointer to screen points list
  824.     double *stereo_point2D = *((double **)
  825.                         stereo_vertices->NthItem(2));            //  2D stereo vertex list
  826.  
  827.     short pane_left;
  828.     short pane_right;
  829.     short pane_top;
  830.     short pane_bottom;
  831.     short other_pane_left;
  832.     short other_pane_right;
  833.     short other_pane_top;
  834.     short other_pane_bottom;
  835.  
  836.     short pane_width;
  837.     switch (pane->StereoMode)
  838.         {
  839.         case mono:                                                //  Use area once
  840.         
  841.             pane_left = pane->frame.left;
  842.             pane_right = pane->frame.right;
  843.             pane_top = pane->frame.top;
  844.             pane_bottom = pane->frame.bottom;
  845.         
  846.             break;
  847.         
  848.         case two_image_stereo:                                    //  Split pane into two areas
  849.     
  850.             pane_width = pane->frame.right - pane->frame.left;
  851.  
  852.             pane_right = pane->frame.right;
  853.             pane_left = pane_right - pane_width/2;
  854.             
  855.             other_pane_top = pane_top = pane->frame.top;
  856.             other_pane_bottom = pane_bottom = pane->frame.bottom;
  857.         
  858.             other_pane_right = pane_left;
  859.             other_pane_left = pane_left - pane_width/2;
  860.             
  861.             break;
  862.  
  863.         case two_color_stereo:                                    //  Use same area twice
  864.  
  865.             other_pane_left = pane_left = pane->frame.left;
  866.             other_pane_right = pane_right = pane->frame.right;
  867.             other_pane_top = pane_top = pane->frame.top;
  868.             other_pane_bottom = pane_bottom = pane->frame.bottom;
  869.         
  870.             break;
  871.         }
  872.     
  873.     long i;
  874.     for (i = 1; i <= num_vertices; i++)
  875.         {
  876.  
  877.         screen_points->h = pane_left +
  878.                             (pane_right - pane_left) *
  879.                                 (*points2D - xmin) / (xmax - xmin);
  880.         
  881.         points2D++;
  882.         
  883.         screen_points->v = pane_bottom -
  884.                             (pane_bottom - pane_top) *
  885.                                 (*points2D - ymin) / (ymax - ymin);
  886.         
  887.         points2D++;
  888.         screen_points++;
  889.  
  890.         }
  891.  
  892.     if (pane->StereoMode != mono)                                    //  Fit the other stereo image
  893.         {
  894.  
  895.         screen_points = *((Point **) stereo_vertices->FirstItem());    //  Get pointer to screen points list
  896.         points2D = *((double **) stereo_vertices->NthItem(2));        //  Get pointer to 2D points list
  897.     
  898.         for (i = 1; i <= num_vertices; i++)
  899.             {
  900.     
  901.             screen_points->h = other_pane_left +
  902.                                 (other_pane_right - other_pane_left) *
  903.                                     (*points2D - xmin) / (xmax - xmin);
  904.             
  905.             points2D++;
  906.             
  907.             screen_points->v = other_pane_bottom -
  908.                                 (other_pane_bottom - other_pane_top) *
  909.                                     (*points2D - ymin) / (ymax - ymin);
  910.             
  911.             points2D++;
  912.             screen_points++;
  913.     
  914.             }        
  915.         }
  916.  
  917. }    //==== FitToPane() ====\\
  918.  
  919.